<template>
  <el-dialog
    :visible.sync="dialogVisible"
    width="600px"
    :before-close="handleClose"
    :close-on-click-modal="false">
    <span slot="title" style="color:#303753;font-size:14px;font-weight:600">发送文件</span>
    <div style="text-align: center; margin-top: -20px">
      <el-alert :title="`是否发送${fileSrc.length > 1 ? ('以下' + fileSrc.length + '个') : '该'}文件?`" type="warning" show-icon :closable="false"></el-alert>
      <div class="notice-attachs">
        <draggable v-model="fileSrc" animation="150" ghostClass="dragClass">
          <div class="download-attach" v-for="(item, index) in fileSrc" :key="index" title="拖动排序">
            <div class="attach-type" v-fileSvg="item.fileName"></div>
            <div class="attach-detail">
              <p class="attach-name">{{ item.fileName }}</p>
              <p class="attach-size">{{ item.size }}
                <span v-if="item.status === 'upload'">(上传进度：{{ item.percent }}%)</span>
                <span v-if="item.status === 'error'" @click="upload(item, index)">(上传失败，点击重新上传)</span>
              </p>
            </div>
            <div class="attach-delete" title="删除" @click="deleteAttach(index)" v-if="!loading && fileSrc.length > 1"><i style="font-size:12px" class="V7_iconfont V7_iconV7tubiao_guanbi"></i></div>

          </div>
        </draggable>
      </div>
    </div>
    <span slot="footer" class="dialog-footer">
      <el-button @click="handleClose">取 消</el-button>
      <el-button type="primary" @click="submit" :loading="loading">确 定</el-button>
    </span>
  </el-dialog>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { uploadQiniu } from '@/utils/upload'
import draggable from 'vuedraggable'
const imgList = ['png', 'jpg', 'gif', 'jpeg', 'bmp']
const fileList = ['txt', 'xlsx', 'xls', 'docx', 'doc', 'pdf', 'ppt', 'pptx', 'key', 'mp3', 'wave', 'mpeg', 'midi', 'mp4', 'zip']
/**
 * 输入框拖拽文件上传组件
 *
 * 1、根据传入渠道，设置不同的最大上传大小
 *
 * 2、支持多个文件的拖入，可删除，调整文件顺序
 *
 * 3、支持文件类型['txt', 'xlsx', 'xls', 'docx', 'doc', 'pdf', 'ppt', 'pptx', 'key', 'mp3', 'wave', 'mpeg', 'midi', 'mp4', 'zip']
 *
 * 4、点击确定按钮，进行文件的上传，任一文件上传失败，可以重新上传，也可以忽略失败文件直接发送
 * @Prop webchatInfo 消息渠道
 */
@Component({
  name: 'DropFile',
  components: { draggable }
})
export default class DropFile extends Vue {
  [x: string]: any
  @Prop() private webchatInfo: any
  private fileSrc: any = []
  private dialogVisible: boolean = false
  private maxSize = 50 // 文件最大大小
  private imgMaxSize = 10 // 图片最大大小
  private loading: boolean = false
  private firstError: boolean = true // 第一次上传出现错误提示，后面不在提示
  private uploadList: any = [] // 保存上传实例，销毁时使用

  private mounted () {
    this.addDropEvent()
  }

  private activated () {
    this.addDropEvent()
  }

  @Watch('webchatInfo', { immediate: true })
  private webchatInfoChange (val) {
    if (['wxkf', 'wxwork'].includes(val.platform)) { // 微信客服和企业微信渠道
      this.maxSize = 20
      this.imgMaxSize = 10
    } else if (val.platform === 'weixin') { // 微信渠道
      this.maxSize = 10
    } else if (val.platform === 'wxmini') { // 微信小程序
      this.maxSize = 10
    } else if (val.platform === 'ocpc') { // 百度bcp渠道
      this.maxSize = 0
    } else {
      this.maxSize = 50
    }
  }

  private destroyed () {
    this.removeDropEvent()
  }

  private deleteAttach (index) {
    this.fileSrc.splice(index, 1)
  }

  private handleClose () {
    this.uploadList.forEach(element => {
      try {
        element.then(res => res.unsubscribe())
      } catch (e) {
        console.log('取消上传')
      }
    });
    this.fileSrc = []
    this.loading = false
    this.dialogVisible = false
    this.firstError = true
  }

  /**
   * 上传单个文件
   * status: upload(上传中) error(上传失败) ok(上传完成)
   */
  private upload (params: any, index: number) {
    this.$set(this.fileSrc[index], 'status', 'upload')
    const request = {
      file: params.file,
      onError: () => {
        this.$set(this.fileSrc[index], 'status', 'error')
        this.$set(this.fileSrc[index], 'percent', 0)
        this.sendMsg()
      },
      onProgress: ({ percent }) => {
        this.$set(this.fileSrc[index], 'percent', percent.toFixed(2))
      },
      onSuccess: (data: any) => {
        if (data.key) {
          this.$set(this.fileSrc[index], 'url', data.key)
          this.$set(this.fileSrc[index], 'status', 'ok')
          this.sendMsg()
        } else {
          return false
        }
      }
    }
    const subscription = uploadQiniu({ type: 'im', fileName: params.fileName }, request)
    this.uploadList.push(subscription)
  }

  // 发送消息
  private async submit () {
    this.loading = true
    this.fileSrc.forEach(async (v, index) => {
      this.upload(v, index)
    })
  }

  // 轮询检测文件是否上传完成，执行发送消息步骤
  private sendMsg () {
    if (this.fileSrc.some(v => v.status === 'upload')) {
      return
    }
    if (this.firstError && this.fileSrc.some(v => v.status === 'error')) {
      this.firstError = false
      this.loading = false
      return
    }
    this.fileSrc.forEach(v => {
      if (v.status === 'ok') {
        if (imgList.includes(v.ext)) {
          (this.$parent as any).uploadImgSuccess({ key: v.url })
        } else {
          (this.$parent as any).dropFileSuccess(v)
        }
      }
    })
    this.loading = false
    this.handleClose()
  }

  private addDropEvent () {
    if (document.getElementById('webchatSendMsg')) {
      (document.getElementById('webchatSendMsg') as any).addEventListener('paste', this.pastFunction);
      (document.getElementById('webchatSendMsg') as any).addEventListener('drop', this.dropFunction)
    }
  }

  private removeDropEvent () {
    if (document.getElementById('webchatSendMsg')) {
      (document.getElementById('webchatSendMsg') as any).removeEventListener('paste', this.pastFunction);
      (document.getElementById('webchatSendMsg') as any).removeEventListener('drop', this.dropFunction)
    }
  }

  private pastFunction (event: any) {
    this.commonFunction(event, 'paste')
  }

  private dropFunction (event: any) {
    this.commonFunction(event, 'drop')
  }

  /**
   * 粘贴和拖拽事件
   * 粘贴：event.clipboardData.files
   * 拖拽：event.dataTransfer.files
   */
  private commonFunction (event: any, type: string) {
    this.fileSrc = []
    let items: any = []
    if (type === 'paste') {
      items = [...event.clipboardData.files]
    } else if (type === 'drop') {
      items = [...event.dataTransfer.files]
    }
    // 区分纯图片上传和文件图片混合上传，使用不同的处理方式
    let other = false
    const list: any = []
    items.forEach(v => {
      const fileName = v.name
      const size = v.size / 1024 / 1024
      const ext = fileName.split('.').pop()?.toLowerCase()
      if (imgList.includes(ext)) {
        if (v.size > this.imgMaxSize) {
          list.push({ file: v, fileName, size, ext })
        }
      }
      if (fileList.includes(ext)) {
        if (v.size > this.maxSize) {
          other = true
          list.push({ file: v, fileName, size, ext })
        }
      }
    })
    if (!other) {
      return false
    }
    list.map(v => {
      const num = String(v.size).length - String(v.size).indexOf('.') + 1
      if (num > 4) {
        v.size = v.size.toFixed(3) + 'M'
      }
      this.fileSrc.push({ ...v, percent: 0, status: '' })
      this.dialogVisible = true
    })
    if (this.dialogVisible) {
      return false
    }
  }
}
</script>

<style lang="stylus" scoped>
.notice-attachs
    max-height 345px
    overflow auto
    text-align: left
    margin-top 6px
    .dragClass
      opacity 0
    .download-attach
        height: 52px;
        background: #FFFFFF;
        border: 1px solid #EDEDED
        border-radius: 4px
        padding 0 12px
        margin-top 10px
        display: block
        cursor move
        position: relative
        .attach-type
            width: 30px;
            height: 30px;
            margin: 12px
            margin-left: 0px
            margin-top 10px
            float: left
        .attach-detail
            float: left
            padding: 10px 0px
            .attach-name
                font-size: 12px;
                font-family: PingFang SC;
                font-weight: 400;
                color: #151515;
                line-height: 12px
                max-width: 400px;
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            .attach-size
                font-size: 12px
                font-family: PingFang SC
                font-weight: 400
                color: #999999
                line-height: 12px
                margin-top: 6px
                span
                  color $c-main
        .attach-delete
          position: absolute
          width: 12px
          height: 13px
          right: 10px
          top 50%
          margin-top -7px
          color red
          cursor pointer
          display: none
      .download-attach:hover
        .attach-delete
          display: block
</style>
<style>
.dragClass {
  opacity: 0;
}
</style>
